package protocol

import (
	"bytes"
	"encoding/binary"
	"goAdapter/device/commInterface"
	"goAdapter/setting"
	"net"
	"strconv"
	"strings"
	"unsafe"
)

type ProHaasTcpTemplate struct {
	Name string //协议名
	Sid  int    //从机地址
	//UseComIf  bool                                 //是否使用标准通信接口
	comIf     commInterface.CommunicationInterface //通信接口
	isConnect bool
	client    net.Conn
}

type ProHaasTcpDataValueTemplate struct {
	Name     string  //点名
	DataType int     //数据类型
	IVal     int     //如果是int类型，把值存到这里
	FVal     float32 //如果是float类型，把值存到这里
	Text     string  //如果是文本类型，把值存到这里
}
type ProHaasTcpDataValueCTemplate struct {
	Name     [64]byte  //点名
	DataType int32     //数据类型
	IVal     int32     //如果是int类型，把值存到这里
	FVal     float32   //如果是float类型，把值存到这里
	Text     [128]byte //如果是文本类型，把值存到这里
}

var ProHaasTcpDataValueMap = []ProHaasTcpDataValueTemplate{}

func (c *ProHaasTcpTemplate) Construct() {
	c.Name = "haasTCP"
	c.Sid = -1
	c.comIf = nil
	//c.UseComIf = false
	c.isConnect = false
}

func (c *ProHaasTcpTemplate) Init(inf commInterface.CommunicationInterface) bool {
	c.comIf = inf

	if inf.GetType() != commInterface.CommTypeTcpClient {
		setting.ZAPS.Errorf("err comm type")
		return false
	}
	return true
}

func (c *ProHaasTcpTemplate) Connect() bool {

	setting.ZAPS.Debugf("protocol [%s] ip=[%s]", c.Name, c.comIf.GetParam().TcpCParam.IP)

	if !c.comIf.Open() {
		setting.ZAPS.Errorf("无法连接服务器:")
		c.isConnect = false
		return false
	}

	c.isConnect = true
	//只有连接成功后，才能启动这个协程
	go c.handleServerMessage()

	return true
}

func (c *ProHaasTcpTemplate) IsConnect() bool {
	return c.isConnect
}

// 处理服务器主动发送的消息
func (c *ProHaasTcpTemplate) handleServerMessage() {
	buf := make([]byte, unsafe.Sizeof(ProHaasTcpDataValueCTemplate{}))
	for {
		if c.comIf.ReadData(buf) > 0 {
			var msg ProHaasTcpDataValueCTemplate
			err := binary.Read(bytes.NewReader(buf), binary.LittleEndian, &msg)
			if err != nil {
				setting.ZAPS.Errorf("解析结构体时出错:", err)
				break
			}
			name := string(msg.Name[:bytes.IndexByte(msg.Name[:], 0)])

			setting.ZAPS.Debugf("recv data name:%s", name)
			findFlag := false
			for k, v := range ProHaasTcpDataValueMap {
				setting.ZAPS.Debugf("update data from haas dev:%s", v.Name)
				//name := strings.TrimRight(string(msg.Name[:]), "\x00")
				if v.Name == name {
					ProHaasTcpDataValueMap[k].DataType = int(msg.DataType)
					ProHaasTcpDataValueMap[k].IVal = int(msg.IVal)
					ProHaasTcpDataValueMap[k].FVal = msg.FVal
					ProHaasTcpDataValueMap[k].Text = strings.TrimRight(string(msg.Text[:]), "\x00")
					findFlag = true
					break
				}
			}
			if !findFlag {
				//未在已有的数据里找到相同的点名，则新建点表
				dataValue := ProHaasTcpDataValueTemplate{
					Name:     string(msg.Name[:bytes.IndexByte(msg.Name[:], 0)]), //为了将byte数组中0以后的数据去掉，再转成string
					DataType: int(msg.DataType),
					IVal:     int(msg.IVal),
					FVal:     msg.FVal,
					Text:     string(msg.Text[:bytes.IndexByte(msg.Text[:], 0)]),
				}
				setting.ZAPS.Debugf("get new data from haas dev:%s", dataValue.Name)
				ProHaasTcpDataValueMap = append(ProHaasTcpDataValueMap, dataValue)
			}
		}
	}
}

//func (c *ProHaasTcpTemplate) GetUseComIf() bool {
//	return c.UseComIf
//}

const (
	DataTypeHaasNil int = iota //占位用，空
	DataTypeHaasINT            //整型
	DataTypeHaasFloat
	DataTypeHaasText
)

var haasTypeMap = map[string]int{"整型": DataTypeHaasINT, "浮点型": DataTypeHaasFloat, "文本型": DataTypeHaasText}

func (c *ProHaasTcpTemplate) GetNode(node *NodeProperty) int {
	if !c.isConnect {
		return -1
	}

	haasDataType := haasTypeMap[node.DataType]
	for _, v := range ProHaasTcpDataValueMap {
		if v.Name == node.RegType {
			switch haasDataType {
			case DataTypeHaasINT:
				node.Value = v.IVal
			case DataTypeHaasFloat:
				node.Value = v.FVal
			case DataTypeHaasText:
				node.Value = v.Text
			}
			break
		}
	}

	return 0
}

func (c *ProHaasTcpTemplate) SetNode(node *NodeProperty) int {
	if !c.isConnect {
		return -1
	}

	haasDataType := haasTypeMap[node.DataType]

	var temp1 [64]byte
	var temp2 [128]byte
	copy(temp1[:], node.RegType)
	dataValue := ProHaasTcpDataValueCTemplate{
		Name:     temp1,
		DataType: int32(haasDataType),
	}

	switch haasDataType {
	case DataTypeHaasINT:
		val, _ := strconv.ParseUint(node.SetValue.(string), 10, 16)
		dataValue.IVal = int32(val)
	case DataTypeHaasFloat:
		val, _ := strconv.ParseFloat(node.SetValue.(string), 16)
		dataValue.FVal = float32(val)
	case DataTypeHaasText:
		copy(temp2[:], node.SetValue.(string))
		dataValue.Text = temp2
	}

	var buf bytes.Buffer
	err := binary.Write(&buf, binary.LittleEndian, &dataValue)
	if err != nil {
		setting.ZAPS.Errorf("Failed to convert struct to []byte:", err)
	}

	if c.comIf.WriteData(buf.Bytes()) == 0 {
		setting.ZAPS.Errorf("发送消息失败")
	}
	return 0
}

func (c *ProHaasTcpTemplate) GetName() string {
	return c.Name
}

func (c *ProHaasTcpTemplate) GetSid() int {
	return c.Sid
}

func (c *ProHaasTcpTemplate) SetSid(id int) {
	c.Sid = id
}

func (c *ProHaasTcpTemplate) GetComInf() commInterface.CommunicationInterface {
	return c.comIf
}
